package chartCraft.model;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;

import chartCraft.Log;

public class TopModel extends Model {
	private static final long serialVersionUID = 1L;

	public static final String INSERT_NEW_LOCATION_MODEL = "insert new location";
	public static final String DELETE_LOCATION_MODEL = "delete location";
	public static final String NO_OF_TIME_UPDATED = "no of time updated";
	public static final String CURRENT_TIME_UPDATED = "current time updated";
	public static final String BACKGROUND_MOVED = "background moved";
	public static final String BACKGROUND_RESIZED = "background resized";
	public static final String BACKGROUND_SELECTION_STATUS = "background selection status changed";
	public static final String BACKGROUND_DATA_UPDATED = "background data updated";
	public static final String BACKGROUND_HIDDING_CHANGED = "background hidding changed";
	public static final String PLAY_STATUS_CHANGED = "play status changed";
	public static final String PLAY_FRAME_NO_CHANGED = "player frame no changed";
	public static final String CHART_TYPE_CHANGED = "chart type changed";
	public static final String SERIES_COLOR_CHANGED = "series color changed";
	public static final String SERIES_NAME_CHANGED = "series name changed";
	public static final String LAYER_DEPTH_CHANGED = "layer depth changed";




	private final ArrayList<LocationModel> mSelectedLocationModels = new ArrayList<LocationModel>();
	private final ArrayList<LocationModel> mAllLocationModels = new ArrayList<LocationModel>();
	private final ArrayList<LocationModel> mLayerDepth = new ArrayList<LocationModel>();
	private final ArrayList<Color> mSeriesColors = new ArrayList<Color>();
	private final ArrayList<String> mSeriesNames = new ArrayList<String>();

	private transient int mCurrentTimeId = 0;
	private int mNoOfTime = 0;
	private int mChartType;
	//for the background
	private Point mBackgroundLocation;
	private Dimension mBackgroundSize;
	private ImageIcon mBackgroundImage;
	private boolean mIsImageHiding;
	private transient boolean mIsBackgroundSelected;

	//for the player
	private transient boolean mIsPlaying = false;
	private transient double mPlayingFrameNo = 0;

	public TopModel() {
		super();
	}

	public ArrayList<LocationModel> getSelectedLocationModels() {
		return mSelectedLocationModels;
	}

	public ArrayList<LocationModel> getAllLocationModels() {
		return mAllLocationModels;
	}

	public void insertNewLocationModel(LocationModel locationModel) {
		insertNewLocationModel(locationModel, mAllLocationModels.size());
	}

	public void insertNewLocationModel(LocationModel locationModel, int locationOffset) {
		synchronized(mAllLocationModels) {
			mAllLocationModels.add(locationOffset, locationModel);
		}
		NotifyingMessage message = new NotifyingMessage(INSERT_NEW_LOCATION_MODEL, locationModel);
		setChanged();
		notifyObservers(message); 
	}

	public void deleteLocationModel(LocationModel locationModel) {
		synchronized(mAllLocationModels) {
			mAllLocationModels.remove(locationModel);
		}
		NotifyingMessage message = new NotifyingMessage(DELETE_LOCATION_MODEL, locationModel);
		setChanged();
		notifyObservers(message);
	}

	public int getLocationId(LocationModel locationModel) {
		return mAllLocationModels.indexOf(locationModel);
	}

	public int getNoOfLocations() {
		synchronized(mAllLocationModels) {
			return mAllLocationModels.size();
		}
	}

	public int getNoOfSeries() {
		if (getNoOfLocations() > 0) {
			return mAllLocationModels.get(0).getNoOfSeries();
		}
		return 0;
	}

	public LocationModel getChildLocationModel(int location) {
		synchronized(mAllLocationModels) {
			if (location < mAllLocationModels.size()) {
				return mAllLocationModels.get(location);
			}
		}
		Log.e(this, "Invalid location specified for \"getChildLocationModel\"");
		return null;
	}

	public void setNoOfTime(int noOfTime) {
		mNoOfTime = noOfTime;

		NotifyingMessage message = new NotifyingMessage(NO_OF_TIME_UPDATED, noOfTime);
		setChanged();
		notifyObservers(message);
	}

	public int getNoOfTime() {
		return mNoOfTime;
	}

	public void setCurrentTimeId(int timeId) {
		mCurrentTimeId = timeId;

		NotifyingMessage message = new NotifyingMessage(CURRENT_TIME_UPDATED, timeId);
		setChanged();
		notifyObservers(message);
	}

	public int getCurrentTimeId() {
		return mCurrentTimeId;
	}

	public void setImageHiding(boolean flag) {
		if (flag != mIsImageHiding) {
			mIsImageHiding = flag;

			NotifyingMessage message = new NotifyingMessage(BACKGROUND_HIDDING_CHANGED, mBackgroundImage);
			setChanged();
			notifyObservers(message);
		}
	}

	public boolean isImagieHiding() {
		return mIsImageHiding;
	}

	public void setBackgroundImage(Image newImage) {
		if (newImage == null) {
			mBackgroundImage = null;
		} else {
			mBackgroundImage = new ImageIcon(newImage);
		}

		NotifyingMessage message = new NotifyingMessage(BACKGROUND_DATA_UPDATED, mBackgroundImage);
		setChanged();
		notifyObservers(message);
	}

	public Image getBackgroundImage() {
		if (mBackgroundImage == null) {
			return null;
		}

		return mBackgroundImage.getImage();
	}

	public void setBackgroundSize(Dimension newSize) {
		mBackgroundSize = newSize;

		NotifyingMessage message = new NotifyingMessage(BACKGROUND_RESIZED, newSize);
		setChanged();
		notifyObservers(message);
	}

	public Dimension getBackgroundSize() {
		return mBackgroundSize;
	}

	public void setBackgroundLocation(Point mNewLocation) {
		mBackgroundLocation = mNewLocation;

		NotifyingMessage message = new NotifyingMessage(BACKGROUND_MOVED, mNewLocation);
		setChanged();
		notifyObservers(message);		
	}

	public Point getBackgroundLocation() {
		return mBackgroundLocation;
	}

	public void setBackgroundSelected(boolean flag) {
		if (mIsBackgroundSelected != flag) {
			mIsBackgroundSelected = flag;

			NotifyingMessage message = new NotifyingMessage(BACKGROUND_SELECTION_STATUS, flag);
			setChanged();
			notifyObservers(message);
		}
	}

	public boolean mIsBackgroundSelected() {
		return mIsBackgroundSelected;
	}

	public void setPlaying(boolean flag) {
		if (mIsPlaying != flag) {
			mIsPlaying = flag;

			NotifyingMessage message = new NotifyingMessage(PLAY_STATUS_CHANGED, flag);
			setChanged();
			notifyObservers(message);
		}
	}

	public boolean isPlaying() {
		return mIsPlaying;
	}

	public double getFrameNo() {
		return mPlayingFrameNo;
	}

	public void setFrameNo(double frameNo) {
		mPlayingFrameNo = frameNo;

		NotifyingMessage message = new NotifyingMessage(PLAY_FRAME_NO_CHANGED, frameNo);
		setChanged();
		notifyObservers(message);
	}

	public void setChartType(int chartType) {
		if (mChartType != chartType) {
			mChartType = chartType;

			NotifyingMessage message = new NotifyingMessage(CHART_TYPE_CHANGED, chartType);
			setChanged();
			notifyObservers(message);
		}
	}

	public int getChartType() {
		return mChartType;
	}

	public void addColorForSeries(Color color) {
		getSeriesColors().add(color);

		NotifyingMessage message = new NotifyingMessage(SERIES_COLOR_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public Color removeColorOfLastSeries() {
		Color colorRemoved;
		colorRemoved = getSeriesColors().remove(getSeriesColors().size()-1);

		NotifyingMessage message = new NotifyingMessage(SERIES_COLOR_CHANGED, null);
		setChanged();
		notifyObservers(message);

		return colorRemoved;
	}

	public void setColorForSeries(int seriesId, Color color) {
		getSeriesColors().set(seriesId, color);

		NotifyingMessage message = new NotifyingMessage(SERIES_COLOR_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public Color getColorForSeries(int seriesId) {
		return getSeriesColors().get(seriesId);
	}

	public void addNameForSeries(String name) {
		getSeriesNames().add(name);

		NotifyingMessage message = new NotifyingMessage(SERIES_NAME_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public String removeNameOfLastSeries() {
		String nameRemoved;
		nameRemoved = getSeriesNames().remove(getSeriesNames().size()-1);

		NotifyingMessage message = new NotifyingMessage(SERIES_NAME_CHANGED, null);
		setChanged();
		notifyObservers(message);

		return nameRemoved;
	}
	public void setNameForSeries(int seriesId, String name) {
		getSeriesNames().set(seriesId, name);

		NotifyingMessage message = new NotifyingMessage(SERIES_NAME_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public String getNameForSeries(int seriesId) {
		return getSeriesNames().get(seriesId);
	}

	public ArrayList<LocationModel> getLayerDepth() {
		return mLayerDepth;
	}

	public int getDepthOf(LocationModel mModel) {
		return mLayerDepth.indexOf(mModel);
	}

	public int getNoOfDepth() {
		return mLayerDepth.size();
	}

	public void changeDepth(int oldDepth, int newDepth) {
		final LocationModel locationModel = mLayerDepth.remove(oldDepth);
		mLayerDepth.add(newDepth, locationModel);

		NotifyingMessage message = new NotifyingMessage(LAYER_DEPTH_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public void addDepth(LocationModel locationModel, int depth) {
		mLayerDepth.add(depth, locationModel);

		NotifyingMessage message = new NotifyingMessage(LAYER_DEPTH_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public void removeDepth(LocationModel locationModel) {
		mLayerDepth.remove(locationModel);

		NotifyingMessage message = new NotifyingMessage(LAYER_DEPTH_CHANGED, null);
		setChanged();
		notifyObservers(message);
	}

	public ArrayList<Color> getSeriesColors() {
		return mSeriesColors;
	}

	public ArrayList<String> getSeriesNames() {
		return mSeriesNames;
	}



}

